import { useEffect, useRef, useState } from 'react';
import { View, ScrollView, Canvas, Text } from '@tarojs/components';
import Taro, { usePageScroll } from '@tarojs/taro';
import './index.scss';

interface DataItem {
  date: string;
  amount: number; // 成交额（柱，蓝，左轴）
  income: number; // 实收（柱，绿，左轴）
  orders: number; // 订单数（线，橙，右轴）
}

interface ChartProps {
  data: DataItem[];
  widthPerItem?: number;
  height?: number;
  // padding: [top, right, bottom, left]
  padding?: [number, number, number, number];
  // 受控 Y 轴显示
  showYAxis?: { left?: boolean; right?: boolean };
  showTooltip?: boolean;
}

export default function LineBarChart({
  data,
  widthPerItem = 50,
  height = 300,
  padding = [40, 50, 40, 40],
  showYAxis = { left: true, right: true },
  showTooltip,
}: ChartProps) {
  const contentCanvasId = 'line-bar-content';
  const leftAxisCanvasId = 'line-bar-y-left';
  const rightAxisCanvasId = 'line-bar-y-right';

  const [tooltip, setTooltip] = useState<{
    x: number;
    y: number;
    item: DataItem;
    index: number;
  } | null>(null);
  const [visible, setVisible] = useState({
    amount: true,
    income: true,
    orders: true,
  });

  // 受控 padding 从数组读取：[top, right, bottom, left]
  const [topPadding, rightAxisWidth, bottomPadding, leftAxisWidth] =
    padding ?? [40, 50, 40, 40];

  // 受控 Y 轴显示（默认左右都显示）
  const showLeftAxis = showYAxis?.left !== false;
  const showRightAxis = showYAxis?.right !== false;

  const contentWidth = Math.max(data.length * widthPerItem, 1);
  const chartHeight = height - topPadding - bottomPadding;
  const scrollLeftRef = useRef(0);

  // 触摸状态（区分滚动与点击）
  const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(
    null,
  );
  const touchMovedRef = useRef(false);

  // 平滑曲线（Catmull-Rom 转贝塞尔，过点）
  const drawSmoothLine = (ctx: any, points: { x: number; y: number }[]) => {
    const n = points.length;
    if (n === 0) return;
    if (n === 1) {
      ctx.beginPath();
      ctx.arc(points[0].x, points[0].y, 2, 0, Math.PI * 2);
      ctx.fill();
      return;
    }

    const tension = 0.5;
    const factor = (1 - tension) / 6;

    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);

    for (let i = 0; i < n - 1; i++) {
      const p0 = points[i - 1] || points[i];
      const p1 = points[i];
      const p2 = points[i + 1];
      const p3 = points[i + 2] || points[i + 1];

      const cp1x = p1.x + (p2.x - p0.x) * factor;
      const cp1y = p1.y + (p2.y - p0.y) * factor;
      const cp2x = p2.x - (p3.x - p1.x) * factor;
      const cp2y = p2.y - (p3.y - p1.y) * factor;

      ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
    }

    ctx.stroke();
  };

  const drawChart = (highlightIndex: number | null = null) => {
    const contentCtx = Taro.createCanvasContext(contentCanvasId);
    const yLeftCtx = Taro.createCanvasContext(leftAxisCanvasId);
    const yRightCtx = Taro.createCanvasContext(rightAxisCanvasId);

    // 根据可见系列计算轴最大值（避免隐藏后比例失真）
    const leftVals: number[] = [];
    if (visible.amount) leftVals.push(...data.map((d) => d.amount));
    if (visible.income) leftVals.push(...data.map((d) => d.income));
    const rightVals: number[] = visible.orders ? data.map((d) => d.orders) : [];

    const maxAmount = Math.max(1, ...(leftVals.length ? leftVals : [1]));
    const maxOrders = Math.max(1, ...(rightVals.length ? rightVals : [1]));

    // 绘制左侧Y轴（固定、受控显示）
    if (showLeftAxis) {
      yLeftCtx.clearRect(0, 0, leftAxisWidth, height);
      yLeftCtx.setStrokeStyle('#ccc');
      yLeftCtx.setLineWidth(1);
      yLeftCtx.beginPath();
      yLeftCtx.moveTo(leftAxisWidth - 1, topPadding);
      yLeftCtx.lineTo(leftAxisWidth - 1, height - bottomPadding);
      yLeftCtx.stroke();

      yLeftCtx.setFillStyle('#7c7c7c');
      yLeftCtx.setFontSize(10);
      for (let i = 0; i <= 5; i++) {
        const y = topPadding + (chartHeight / 5) * i;
        const val = Math.round(maxAmount - (maxAmount / 5) * i);
        yLeftCtx.fillText(String(val), 6, y + 3);
      }
      yLeftCtx.draw();
    } else {
      // 隐藏时清空画布
      yLeftCtx.clearRect(0, 0, leftAxisWidth, height);
      yLeftCtx.draw();
    }

    // 绘制右侧Y轴（固定、受控显示）
    if (showRightAxis) {
      yRightCtx.clearRect(0, 0, rightAxisWidth, height);
      yRightCtx.setStrokeStyle('#ccc');
      yRightCtx.setLineWidth(1);
      yRightCtx.beginPath();
      yRightCtx.moveTo(1, topPadding);
      yRightCtx.lineTo(1, height - bottomPadding);
      yRightCtx.stroke();

      yRightCtx.setFillStyle('#7c7c7c');
      yRightCtx.setFontSize(10);
      for (let i = 0; i <= 5; i++) {
        const y = topPadding + (chartHeight / 5) * i;
        const val = Math.round(maxOrders - (maxOrders / 5) * i);
        yRightCtx.fillText(String(val), 10, y + 3);
      }
      yRightCtx.draw();
    } else {
      yRightCtx.clearRect(0, 0, rightAxisWidth, height);
      yRightCtx.draw();
    }

    // 中间内容区域（可横向滚动）
    const gap = Math.max(1, Math.round(widthPerItem / 10));
    const barWidth = Math.max(2, Math.floor((widthPerItem - gap) / 4));
    const linePoints: { x: number; y: number }[] = [];

    // X轴基线
    contentCtx.setStrokeStyle('#eee');
    contentCtx.setLineWidth(1);
    contentCtx.beginPath();
    contentCtx.moveTo(0, height - bottomPadding);
    contentCtx.lineTo(contentWidth, height - bottomPadding);
    contentCtx.stroke();

    // 高亮列背景
    if (highlightIndex !== null) {
      const xHl = highlightIndex * widthPerItem;
      contentCtx.setFillStyle('rgba(0,0,0,0.04)');
      contentCtx.fillRect(xHl, topPadding, widthPerItem, chartHeight);
    }

    // 柱 & 线点 & X 轴文字
    data.forEach((item, index) => {
      const xBase = index * widthPerItem + barWidth;

      if (visible.amount) {
        const h1 = (item.amount / maxAmount) * chartHeight;
        contentCtx.setFillStyle('#0a7aff');
        contentCtx.fillRect(xBase, height - bottomPadding - h1, barWidth, h1);
      }

      if (visible.income) {
        const h2 = (item.income / maxAmount) * chartHeight;
        contentCtx.setFillStyle('#34c759');
        contentCtx.fillRect(
          xBase + barWidth + gap,
          height - bottomPadding - h2,
          barWidth,
          h2,
        );
      }

      if (visible.orders) {
        const y =
          height - bottomPadding - (item.orders / maxOrders) * chartHeight;
        linePoints.push({ x: xBase + barWidth, y });
      }

      // X 轴文本（始终绘制在轴线下方）
      contentCtx.setFontSize(10);
      contentCtx.setFillStyle('#7c7c7c');
      contentCtx.setTextAlign('left');
      contentCtx.setTextBaseline('top');
      const rotate = widthPerItem < 60 || data.length > 12;
      if (rotate) {
        contentCtx.save();
        contentCtx.translate(xBase, height - bottomPadding + 4);
        contentCtx.rotate(Math.PI / 4);
        contentCtx.fillText(item.date, 0, 0);
        contentCtx.restore();
      } else {
        contentCtx.fillText(item.date, xBase, height - bottomPadding + 4);
      }
    });

    // 光滑折线
    if (visible.orders && linePoints.length) {
      contentCtx.setStrokeStyle('#ff9500');
      contentCtx.setLineWidth(2);
      drawSmoothLine(contentCtx, linePoints);

      // 折线点
      linePoints.forEach((pt) => {
        contentCtx.setFillStyle('#ff9500');
        contentCtx.beginPath();
        contentCtx.arc(pt.x, pt.y, 3, 0, Math.PI * 2);
        contentCtx.fill();
      });
    }

    contentCtx.draw();
  };

  const getIndexByTouch = (x: number) => {
    const idx = Math.floor(x / widthPerItem);
    if (Number.isNaN(idx)) return null;
    // 将索引夹在 [0, data.length - 1]，避免边缘点击或浮点误差导致的空结果
    return Math.max(0, Math.min(data.length - 1, idx));
  };

  useEffect(() => {
    drawChart(tooltip?.index ?? null);
  }, [data, visible, tooltip]);

  useEffect(() => {
    setTooltip(null);
  }, [data]);

  // 页面（垂直）滚动时隐藏 tooltip
  usePageScroll(() => {
    if (tooltip) setTooltip(null);
  });

  // 滚动时仅记录偏移，不触发同步重绘（避免抖动）
  let rafId: any = null;
  const handleScroll = (e) => {
    const sl = e?.detail?.scrollLeft || 0;
    scrollLeftRef.current = sl;
    if (rafId) return;
    rafId = requestAnimationFrame(() => {
      rafId = null;
      // 避免频繁 draw，在下一帧只绘制一次（不改变高亮索引）
      drawChart(tooltip?.index ?? null);
    });
  };

  const handleTouchStart = (e) => {
    const t = e.touches?.[0];
    if (!t) return;
    touchStartRef.current = { x: t.clientX, y: t.clientY, time: Date.now() };
    touchMovedRef.current = false;
  };

  const handleTouchMove = (e) => {
    const t = e.touches?.[0];
    if (!t || !touchStartRef.current) return;
    const dx = Math.abs(t.clientX - touchStartRef.current.x);
    const dy = Math.abs(t.clientY - touchStartRef.current.y);
    if (dx + dy > 10) {
      touchMovedRef.current = true;
      if (tooltip) {
        setTooltip(null);
      }
    }
  };

  const handleTouchEnd = (e) => {
    // 滚动手势：不显示 tooltip，不重绘高亮
    if (touchMovedRef.current) {
      setTooltip(null);
      drawChart();
      return;
    }

    // 轻点手势：计算索引（使用滚动容器 rect + scrollLeft，避免偏差）
    const changedTouch = e.changedTouches?.[0];
    if (!changedTouch) return;
    const query = Taro.createSelectorQuery();
    query.select('.chart-content-scroll').boundingClientRect();
    query.select('.chart-content-scroll').scrollOffset();
    query.select('.chart-container').boundingClientRect();
    query.exec((res: any[]) => {
      const scrollRect = res?.[0];
      const scrollInfo = res?.[1];
      const containerRect = res?.[2];
      if (!scrollRect || !containerRect) return;
      const localX = changedTouch.clientX - scrollRect.left;
      const sl =
        (scrollInfo && (scrollInfo.scrollLeft ?? scrollInfo.scrollX)) || 0;
      const xGlobal = sl + localX;
      const idx = getIndexByTouch(xGlobal);
      if (idx == null) return;

      // Toggle: 点击同一根柱子则隐藏 tooltip，并清除高亮
      if (tooltip && tooltip.index === idx) {
        setTooltip(null);
        drawChart();
        return;
      }

      // tooltip 相对容器定位
      const rawLeft = changedTouch.clientX - containerRect.left - 80;
      const rawTop = scrollRect.top - containerRect.top + 30;
      const rows =
        1 +
        (visible.amount ? 1 : 0) +
        (visible.income ? 1 : 0) +
        (visible.orders ? 1 : 0);
      const approxWidth = 180; // 近似宽度
      const approxHeight = 24 + rows * 22; // 近似高度
      const pad = 8;
      const clampedLeft = Math.min(
        Math.max(rawLeft, pad),
        containerRect.width - approxWidth - pad,
      );
      const clampedTop = Math.min(
        Math.max(rawTop, pad),
        containerRect.height - approxHeight - pad,
      );

      setTooltip({
        x: clampedLeft,
        y: clampedTop,
        item: data[idx],
        index: idx,
      });
      drawChart(idx);
    });
  };

  const toggleLegend = (key: 'amount' | 'income' | 'orders') => {
    setVisible((v) => ({ ...v, [key]: !v[key] }));
  };

  return (
    <View className="chart-container">
      <View
        className="chart-row"
        style={{ display: 'flex', width: '100%', height: `${height}px` }}
      >
        <View
          className="chart-fixed-y-wrap"
          style={{
            width: `${showLeftAxis ? leftAxisWidth : 0}px`,
            height: `${height}px`,
          }}
        >
          {showLeftAxis && (
            <Canvas
              id={leftAxisCanvasId}
              canvasId={leftAxisCanvasId}
              className="chart-fixed-y"
              style={{
                width: '100%',
                height: '100%',
                display: 'block',
                willChange: 'transform',
              }}
              width={`${leftAxisWidth}`}
              height={`${height}`}
            />
          )}
        </View>

        <ScrollView
          scrollX
          className="chart-content-scroll"
          style={{ flex: 1 }}
          onScroll={handleScroll}
        >
          <Canvas
            id={contentCanvasId}
            canvasId={contentCanvasId}
            style={{
              width: `${contentWidth}px`,
              height: `${height}px`,
              display: 'block',
              willChange: 'transform',
            }}
            width={`${contentWidth}`}
            height={`${height}`}
            onTouchStart={handleTouchStart}
            onTouchMove={handleTouchMove}
            onTouchEnd={handleTouchEnd}
          />
        </ScrollView>

        <View
          className="chart-fixed-y-wrap"
          style={{
            width: `${showRightAxis ? rightAxisWidth : 0}px`,
            height: `${height}px`,
          }}
        >
          {showRightAxis && (
            <Canvas
              id={rightAxisCanvasId}
              canvasId={rightAxisCanvasId}
              className="chart-fixed-y"
              style={{
                width: '100%',
                height: '100%',
                display: 'block',
                willChange: 'transform',
              }}
              width={`${rightAxisWidth}`}
              height={`${height}`}
            />
          )}
        </View>
      </View>

      {/* Tooltip */}
      {tooltip && showTooltip && (
        <View className="tooltip" style={{ top: tooltip.y, left: tooltip.x }}>
          <View className="tooltip-date">{tooltip.item.date}</View>
          {visible.amount && (
            <View className="tooltip-row">
              <View className="dot blue" />
              成交额
              <View className="tooltip-value">
                {tooltip.item.amount}
                <Text className="tooltip-unit">元</Text>
              </View>
            </View>
          )}
          {visible.income && (
            <View className="tooltip-row">
              <View className="dot green" />
              实收
              <View className="tooltip-value">
                {tooltip.item.income}
                <Text className="tooltip-unit">元</Text>
              </View>
            </View>
          )}
          {visible.orders && (
            <View className="tooltip-row">
              <View className="dot orange" />
              订单数
              <View className="tooltip-value">
                {tooltip.item.orders}
                <Text className="tooltip-unit">单</Text>
              </View>
            </View>
          )}
        </View>
      )}

      {/* Legend */}
      <View className="legend">
        <View
          className={`legend-item ${visible.amount ? '' : 'disabled'}`}
          onClick={() => toggleLegend('amount')}
        >
          <View className="dot blue" />
          成交额
        </View>
        <View
          className={`legend-item ${visible.income ? '' : 'disabled'}`}
          onClick={() => toggleLegend('income')}
        >
          <View className="dot green" />
          实收
        </View>
        <View
          className={`legend-item ${visible.orders ? '' : 'disabled'}`}
          onClick={() => toggleLegend('orders')}
        >
          <View className="dot orange" />
          订单数
        </View>
      </View>
    </View>
  );
}
